Skip to content

Method: ContentLengthUpdater(OutputStream, long)

1: /*
2: * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
3: *
4: * This program and the accompanying materials are made available under the
5: * terms of the Eclipse Public License v. 2.0, which is available at
6: * http://www.eclipse.org/legal/epl-2.0.
7: *
8: * This Source Code may also be made available under the following Secondary
9: * Licenses when the conditions for such availability set forth in the
10: * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
11: * version 2 with the GNU Classpath Exception, which is available at
12: * https://www.gnu.org/software/classpath/license.html.
13: *
14: * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15: */
16:
17: package org.eclipse.angus.mail.mbox;
18:
19: import java.io.FilterOutputStream;
20: import java.io.IOException;
21: import java.io.OutputStream;
22: import java.nio.charset.StandardCharsets;
23:
24: /**
25: * Update the Content-Length header in the message written to the stream.
26: */
27: class ContentLengthUpdater extends FilterOutputStream {
28: private String contentLength;
29: private boolean inHeader = true;
30: private boolean sawContentLength = false;
31: private int lastb1 = -1, lastb2 = -1;
32: private StringBuilder line = new StringBuilder();
33:
34: public ContentLengthUpdater(OutputStream os, long contentLength) {
35: super(os);
36: this.contentLength = "Content-Length: " + contentLength;
37: }
38:
39: public void write(int b) throws IOException {
40: if (inHeader) {
41: String eol = "\n";
42: // First, determine if we're still in the header.
43: if (b == '\r') {
44: // if line terminator is CR
45: if (lastb1 == '\r') {
46: inHeader = false;
47: eol = "\r";
48: // else, if line terminator is CRLF
49: } else if (lastb1 == '\n' && lastb2 == '\r') {
50: inHeader = false;
51: eol = "\r\n";
52: }
53: // else, if line terminator is \n
54: } else if (b == '\n') {
55: if (lastb1 == '\n') {
56: inHeader = false;
57: eol = "\n";
58: }
59: }
60:
61: // If we're no longer in the header, and we haven't seen
62: // a Content-Length header yet, it's time to put one out.
63: if (!inHeader && !sawContentLength) {
64: out.write(contentLength.getBytes(StandardCharsets.ISO_8859_1));
65: out.write(eol.getBytes(StandardCharsets.ISO_8859_1));
66: }
67:
68: // If we have a full line, see if it's a Content-Length header.
69: if (b == '\r' || (b == '\n' && lastb1 != '\r')) {
70: if (line.toString().regionMatches(true, 0,
71: "content-length:", 0, 15)) {
72: // yup, got it
73: sawContentLength = true;
74: // put out the new version
75: out.write(contentLength.getBytes(StandardCharsets.ISO_8859_1));
76: } else {
77: // not a Content-Length header, just write it out
78: out.write(line.toString().getBytes(StandardCharsets.ISO_8859_1));
79: }
80: line.setLength(0); // clear buffer for next line
81: }
82: if (b == '\r' || b == '\n')
83: out.write(b); // write out line terminator immediately
84: else
85: line.append((char) b); // accumulate characters of the line
86:
87: // rotate saved characters for next time through loop
88: lastb2 = lastb1;
89: lastb1 = b;
90: } else
91: out.write(b); // not in the header, just write it out
92: }
93:
94: public void write(byte[] b) throws IOException {
95: if (inHeader)
96: write(b, 0, b.length);
97: else
98: out.write(b);
99: }
100:
101: public void write(byte[] b, int off, int len) throws IOException {
102: if (inHeader) {
103: for (int i = 0; i < len; i++) {
104: write(b[off + i]);
105: }
106: } else
107: out.write(b, off, len);
108: }
109:
110: // for testing
111: public static void main(String[] argv) throws Exception {
112: int b;
113: ContentLengthUpdater os =
114: new ContentLengthUpdater(System.out, Long.parseLong(argv[0]));
115: while ((b = System.in.read()) >= 0)
116: os.write(b);
117: os.flush();
118: }
119: }